#include <iostream>
#include <functional>
using namespace std;

template<class T>
class Auto_ptr
{
public:
    Auto_ptr(T* ptr)
    :_ptr(ptr)
    {}
    ~Auto_ptr()
    {
        if(_ptr)
        {
            delete _ptr;
        }
    }
    Auto_ptr(Auto_ptr<T>& ptr)
    :_ptr(ptr._ptr)
    {
        ptr._ptr = nullptr;
    }
    Auto_ptr<T>& operator=(Auto_ptr<T>& ptr)
    {
        if (this != &ptr)
        {
            delete _ptr;       //释放自己管理的资源
            _ptr = ptr._ptr;    //接管ap对象的资源
            ptr._ptr = nullptr; //管理权转移后ap被置空
        }
        return *this;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    T *_ptr;
};

template<class T>
class Unique_ptr
{
public:
    Unique_ptr(T* ptr)
    :_ptr(ptr)
    {}
    ~Unique_ptr()
    {
        if(_ptr)
        {
            delete _ptr;
        }
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    Unique_ptr(Unique_ptr<T> &ptr) = delete;
    Unique_ptr<T>& operator=(Unique_ptr<T> &ptr) = delete;
private:
    T *_ptr;
};

template<class T>
class Shared_ptr
{
public:
    using func = function<void(T*)>;
    Shared_ptr(T *ptr)
        : _ptr(ptr), _count(new int(1))
    {}
    template<class D>
    Shared_ptr(T *ptr,D del)
        : _ptr(ptr), _count(new int(1)),_del(del)
    {}
    ~Shared_ptr()
    {
        (*_count)--;
        if((*_count) == 0)
        {
            if(_ptr)
            {
                delete _ptr;
                _ptr = nullptr;
            }
            delete _count;
            _count = nullptr;
        }
    }
    Shared_ptr(Shared_ptr<T>& ptr)
    :_ptr(ptr._ptr)
    ,_count(ptr._count)
    {
        ptr._count--;
    }
    Shared_ptr<T>& operator=(Shared_ptr<T>& ptr)
    {
        if(&ptr == this) return ptr;
        ptr._count--;
        if(ptr._count == 0)
        {
            delete ptr._count;
            delete ptr._count;
        }
        _ptr = ptr._ptr;
        _count = ptr._count;
        _count++;
        return *this;
    }
    T& operator*() { return *_ptr; }
    T* operator->() { return _ptr; }
    T* get()
    {
        return _ptr;
    }

private:
    T *_ptr;
    int* _count;
    func _del;
};

template<class T>
class Weak_ptr
{
public:
    Weak_ptr() {}
    Weak_ptr(Shared_ptr<T>& ptr)
    {
        _ptr = ptr.get();
    }
    // ~Weak_ptr()
    // {
    //     if(_ptr != nullptr)
    //     {
    //         delete _ptr;
    //         //_ptr = nullptr;
    //     }
    // }
    Weak_ptr<T>& operator=(Shared_ptr<T>* ptr)
    {
        _ptr = ptr.get();
        return *this;
    }
    T& operator*() { return *_ptr; }
    T* operator->() { return _ptr; }
private:
    T *_ptr;
};
